package com.jichangxiu.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.jichangxiu.common.annotation.Dynamic;
import com.jichangxiu.common.annotation.Scope;
import com.jichangxiu.common.exception.ServiceException;
import com.jichangxiu.common.utils.ConvertUtils;
import com.jichangxiu.system.entity.bo.SysTypeBo;
import com.jichangxiu.system.entity.dto.add.AddSysType;
import com.jichangxiu.system.entity.dto.edit.EditSysType;
import com.jichangxiu.system.entity.dto.query.QuerySysType;
import com.jichangxiu.system.entity.po.SysData;
import com.jichangxiu.system.entity.po.SysType;
import com.jichangxiu.system.entity.vo.SysDataVo;
import com.jichangxiu.system.entity.vo.SysTypeVo;
import com.jichangxiu.system.enums.DictType;
import com.jichangxiu.system.mapper.SysTypeMapper;
import com.jichangxiu.system.service.SysDataService;
import com.jichangxiu.system.service.SysTypeService;
import com.jichangxiu.framework.utils.SecurityUtils;
import com.jichangxiu.framework.utils.NoUtils;
import com.jichangxiu.common.entity.bo.ValidateBos;
import com.jichangxiu.framework.service.impl.BaseServiceImpl;
import com.jichangxiu.framework.utils.ValidateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * SysTypeServiceImpl:
 *
 * @author JiChangXiu
 * @create 2024-06-28 13:44:54
 */
@Service
public class SysTypeServiceImpl extends BaseServiceImpl<SysTypeMapper, SysType, SysTypeVo> implements SysTypeService {

    @Resource
    private SysDataService sysDataService;

    /**
     * 新增系统类型
     *
     * @param addSysType 新增系统类型视图对象
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(AddSysType addSysType) {
        return getBaseMapper().insert(addAndEditValidBo(ConvertUtils.convert(addSysType, SysTypeBo.class))) > 0;
    }

    /**
     * 单（多）选删除系统类型
     *
     * @param idList 系统类型主键列表
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean del(List<String> idList) {
        return getBaseMapper().deleteBatchIds(delValid(idList)) > 0;
    }

    /**
     * 修改系统类型
     *
     * @param editSysType 修改系统类型视图对象
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean edit(EditSysType editSysType) {
        return getBaseMapper().updateById(addAndEditValidBo(ConvertUtils.convert(editSysType, SysTypeBo.class))) > 0;
    }

    /**
     * 根据主键查询系统类型
     *
     * @param id       系统类型主键
     * @param isExtend 是否扩展
     * @return 系统类型详情
     */
    @Dynamic
    @Override
    public SysTypeVo info(@NotBlank(message = "主键不能为空") String id, Boolean isExtend) {
        SysTypeVo sysTypeVo = getBaseMapper().selectJoinOne(SysTypeVo.class, buildQueryWrapper(QuerySysType.builder().id(id).build()));
        if (Boolean.TRUE.equals(isExtend) && ObjectUtil.isNotEmpty(sysTypeVo))
            sysTypeVo = renderSysTypeVoList(ListUtil.toList(sysTypeVo)).get(0);
        return sysTypeVo;
    }

    /**
     * 根据标识查询系统类型
     *
     * @param code     系统类型标识
     * @param isExtend 是否扩展
     * @return 系统类型详情
     */
    @Dynamic
    @Override
    public SysTypeVo infoByCode(String code, Boolean isExtend) {
        SysTypeVo sysTypeVo = getBaseMapper().vo(new LambdaQueryWrapper<SysType>().eq(SysType::getCode, code));
        if (Boolean.TRUE.equals(isExtend) && ObjectUtil.isNotEmpty(sysTypeVo))
            sysTypeVo = renderSysTypeVoList(ListUtil.toList(sysTypeVo)).get(0);
        return sysTypeVo;
    }

    /**
     * （可分页）查询系统类型列表
     *
     * @param querySysType 查询视图对象
     * @return （分页）系统类型列表
     */
    @Dynamic
    @Override
    public Page<SysTypeVo> lists(QuerySysType querySysType) {
        Page<SysTypeVo> sysTypeVoPage = getBaseMapper().selectJoinPage(startPage(), SysTypeVo.class, buildQueryWrapper(querySysType));
        if (Boolean.TRUE.equals(querySysType.getIsExtend()))
            sysTypeVoPage.setRecords(renderSysTypeVoList(sysTypeVoPage.getRecords()));
        return sysTypeVoPage;
    }

    /**
     * 新增 / 修改 前校验
     *
     * @param sysTypeBo 校验用业务对象
     * @return 数据库操作对象
     */
    private SysType addAndEditValidBo(SysTypeBo sysTypeBo) {
        SysType sysType = ConvertUtils.convert(sysTypeBo, SysType.class);
        if (ObjectUtil.isNull(sysType))
            throw new ServiceException("待校验对象为空");
        List<ValidateBos> validateBosList = Stream.of(
                ValidateUtils.createNeValidateBos(ValidateUtils.createValidateBo(SysType::getId, sysType.getId(), "主键")),
                ValidateUtils.createOrEqValidateBos(
                        ValidateUtils.createValidateBo(SysType::getNo, sysType.getNo(), "编码"),
                        ValidateUtils.createValidateBo(SysType::getCode, sysType.getCode(), "标识"),
                        ValidateUtils.createValidateBo(SysType::getName, sysType.getName(), "名称"),
                        ValidateUtils.createValidateBo(SysType::getRemark, sysType.getRemark(), "备注"))
        ).collect(Collectors.toList());
        // 唯一校验
        ValidateUtils.uniqueValidate(this::countWrapper, validateBosList);
        if (DictType.SYSTEM_DICT.name().equals(sysType.getType()))
            sysType.setUserId(null);
        else if (DictType.USER_DICT.name().equals(sysType.getType()))
            sysType.setUserId(SecurityUtils.getUserId());
        if (StrUtil.isEmpty(sysType.getId())) {
            // 新增
            sysType.setNo(NoUtils.createNo(SecurityUtils.getTenantId(), "dict"));
            sysType.setTenantId(SecurityUtils.getTenantId());
            return sysType;
        } else {
            // 修改
            SysType dbSysType = getById(sysType.getId());
            BeanUtil.copyProperties(sysType, dbSysType, true);
            return dbSysType;
        }
    }

    /**
     * 删除前校验
     *
     * @param idList 主键列表
     * @return 主键列表
     */
    private List<String> delValid(List<String> idList) {
        if (ObjectUtil.isEmpty(idList))
            throw new ServiceException("待校验主键列表为空");
        if (sysDataService.count(new LambdaQueryWrapper<SysData>().in(SysData::getTypeId, idList)) != 0)
            throw new ServiceException("尚有字典下还存在字典值，不能删除");
        return idList;
    }

    /**
     * 渲染视图
     *
     * @param sysTypeVoList 视图列表
     * @return 渲染后的视图列表
     */
    private List<SysTypeVo> renderSysTypeVoList(List<SysTypeVo> sysTypeVoList) {
        if (ObjectUtil.isNotEmpty(sysTypeVoList)) {
            // todo 扩展信息填入
            List<SysDataVo> sysDataVoList = sysDataService.voList(new LambdaQueryWrapper<SysData>().in(SysData::getTypeId, sysTypeVoList.stream().map(SysTypeVo::getId).collect(Collectors.toList())));
            if (ObjectUtil.isNotEmpty(sysDataVoList)) {
                Map<String, List<SysDataVo>> typeIdBySysDataVoListToMap = sysDataVoList.stream().collect(Collectors.groupingBy(SysDataVo::getTypeId));
                sysTypeVoList.forEach(sysTypeVo -> sysTypeVo.setSysDataVoList(typeIdBySysDataVoListToMap.get(sysTypeVo.getId())));
            }
        }
        return sysTypeVoList;
    }

    /**
     * 构建查询条件
     *
     * @param querySysType 查询用业务对象
     * @return 查询条件
     */
    private MPJLambdaWrapper<SysType> buildQueryWrapper(QuerySysType querySysType) {
        MPJLambdaWrapper<SysType> lambdaQueryWrapper = new MPJLambdaWrapper<SysType>().selectAll(SysType.class);
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysType.getId()), SysType::getId, querySysType.getId());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysType.getNo()), SysType::getNo, querySysType.getNo());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysType.getCode()), SysType::getCode, querySysType.getCode());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysType.getName()), SysType::getName, querySysType.getName());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysType.getType()), SysType::getType, querySysType.getType());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysType.getUserId()), SysType::getUserId, querySysType.getUserId());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysType.getSort()), SysType::getSort, querySysType.getSort());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysType.getRemark()), SysType::getRemark, querySysType.getRemark());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysType.getEnabled()), SysType::getEnabled, querySysType.getEnabled());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysType.getEnabledBy()), SysType::getEnabledBy, querySysType.getEnabledBy());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysType.getEnabledTime()), SysType::getEnabledTime, querySysType.getEnabledTime());
        lambdaQueryWrapper.apply(StrUtil.isNotEmpty(querySysType.getScope()), querySysType.getScope());
        lambdaQueryWrapper.orderByAsc(SysType::getSort);
        return lambdaQueryWrapper;
    }

}